#include "CudaEpiModel.h"
#include <sys/time.h>
#include <fstream>


bool cuda_run;

void cudaSimulate(EpiModel& model){

	model.prerun(); 
	cudaInitialize(model);
	//model.init_openmp();

	struct timeval begin, finish;
	double t1,t2;
	double day_time = 0;
	double night_time = 0;
	double response_time = 0;
	
	bool gpu_mode = true;
	int pplSymptoticTotal = 0;
	double threshold = -1;

	ofstream timeing_file("timing_file.txt",ios::out);

	while(model.nTimer<model.nRunLength*2) {
    		if (model.nLogFileInterval>0 && (int)(model.nTimer/2)%model.nLogFileInterval==0) model.log();
    		if (model.bSeedDaily) model.seedinfected();
	
		
		cout << "time now is " << model.nTimer << " ---------------------------- " << endl;
		int cur_time = model.nTimer / 2;

		gettimeofday(&begin,NULL);
		
		if(cuda_run){
			if(gpu_mode) cudaDay();
			else model.day();
		}
		//if(cuda_run) cudaDay();
		else model.day();
		
		gettimeofday(&finish,NULL);
		t1 = (double)begin.tv_sec + ((double)begin.tv_usec/1000000.0);
		t2 = (double)finish.tv_sec + ((double)finish.tv_usec/1000000.0);
		day_time += (t2-t1);
		cout << "cudaday: " << (t2 - t1) << endl;
		if(threshold < 0) threshold = t2 - t1;
		cout << "cuda runing status: " << gpu_mode << endl;
		cout << "threshold value: " << threshold << endl;

		gpu_mode = (t2 - t1) > threshold;

		timeing_file << cur_time << " " << (t2-t1) << " ";
		
		if (model.bTravel) model.travel_end();
		model.nTimer++;
    	

		gettimeofday(&begin,NULL);
		model.night();
		gettimeofday(&finish,NULL);
		t1 = (double)begin.tv_sec + ((double)begin.tv_usec/1000000.0);
		t2 = (double)finish.tv_sec + ((double)finish.tv_usec/1000000.0);
		cout << "cudanight: " << (t2 - t1)<< endl;
		night_time += (t2-t1);
		
		timeing_file << (t2-t1) << " ";
		
		
    	if (model.bTravel) model.travel_start();

		gettimeofday(&begin,NULL);
		model.response();
		model.nTimer++; 
		gettimeofday(&finish,NULL);
		t1 = (double)begin.tv_sec + ((double)begin.tv_usec/1000000.0);
		t2 = (double)finish.tv_sec + ((double)finish.tv_usec/1000000.0);
		cout << "cudaresponse: " <<(t2 - t1) << endl;
		response_time += (t2-t1);
	 
		timeing_file << (t2-t1) << endl;

		// start = clock();
		
		// cudaStats();
		
		// cout << "cuda stats: " << ((double)clock() - start)/ CLOCKS_PER_SEC << endl;
		
		unsigned int nNumSymptomatic=0;
		unsigned int nNumCumulativeSymptomatic=0;
		unsigned int nNumInfected = 0;
		for (vector< Community >::iterator it = model.commvec.begin();
			it !=  model.commvec.end();
			it++) {
				for (int j=0; j<TAG; j++) {
					nNumCumulativeSymptomatic += (*it).nEverSymptomatic[j];
					nNumSymptomatic += (*it).nsym[j];
					nNumInfected += (*it).ninf[j];
				}
		}
		pplSymptoticTotal = nNumCumulativeSymptomatic;
		/*cout << "nNumInfected: " << nNumInfected << endl;
		cout << "nNumSymptomatic: " << nNumSymptomatic << endl;
		cout << "nNumCumulativeSymptomatic: " << nNumCumulativeSymptomatic << endl;*/
	
	}
	timeing_file.close();
	/*cout << "day_time takes: " << day_time << " secs" << endl;
	cout << "night_time takes: " << night_time << " secs" << endl;
	cout << "response_time takes: " << response_time<< " secs" << endl;*/
	/*ofstream cuda_sim_info("gpu_sim_info.txt",ios::out|ios::app);
	cuda_sim_info << day_time << " " << pplSymptoticTotal;
	cuda_sim_info.close();*/
}



int main(int argc, char *argv[]) {
	char *configname=NULL;
	char *option=NULL;
	if (argc==3) configname = argv[1];
  	else {
    		cerr << "Usage: " << argv[0] << " configfilename" << endl;
   	 	exit(-1);
  	}
	// cout << "size of int: " << sizeof(int) << endl;
	// cout << "size of ppl: " << sizeof(Person) << endl;
	// cout << "size of Community: " << sizeof(Community) << endl;
	// exit(1);
	
	
  	EpiModelParameters parms(configname);
  	EpiModel model(parms);
	
	// time_t start = clock();
	// cout << "time taken for configuration is " << ((double)clock()-start)/CLOCKS_PER_SEC << " secs" << endl;
	
	option = argv[2];
	cuda_run = atoi(option) == 0;
	cout << "started simulation xxxxxx" << endl;
	cout << "num of person: " << model.nNumPerson << endl;
	cout << "size of person: " << sizeof(Person) << endl;

	cudaSimulate(model);
	
	cout << "finish ... " << endl;
	
	// cout << compareModel(compare_model) << endl;
	clean();
  	return 0;
}
